function Observer(data) {
  this.data = data
  this.walk(data)
}

Observer.prototype = {
  walk: function (data) {
    // 存储Observer实例
    var me = this
    // 遍历data中的所有的键,对data中的数据进行数据劫持
    Object.keys(data).forEach(function (key) {
      me.defineReactive(data, key, data[key])
    })
  },

  // 这个函数是真正进行数据劫持的函数
  defineReactive: function (data, key, val) {
    // 创建一个依赖的实例(?)
    var dep = new Dep()
    // 递归进行数据劫持.比如data中的msg也是一个对象({xxx: 123}).那么msg指向的对象也要进行数据接触,所以递归调用observe
    var childObj = observe(val)
    // 对data的数据进行数据劫持
    Object.defineProperty(data, key, {
      enumerable: true,
      configurable: false,

      get: function () {
        debugger
        // 只要获取data中的数据就会触发这个get
        // 6. 但是要进入到if判断中,是只有new Watcher的时候
        if (Dep.target) {
          // 7. 执行dep.depend的目的就是在watcher中存储dep.在dep中存储watcher
          dep.depend()
        }
        return val
      },
      set: function (newVal) {
        debugger
        if (newVal === val) {
          return
        }

        val = newVal

        childObj = observe(newVal)
        dep.notify()
      },
    })
  },
}

// 进行数据劫持的入口
function observe(value, vm) {
  // 如果传入的第一个参数不是对象,或没有传递参数,则直接return,如果传入的是对象,就继续往下走,进行数据劫持
  if (!value || typeof value !== 'object') {
    return
  }
  // 继续往下走,后面会进行数据劫持的操作
  return new Observer(value)
}

var uid = 0

function Dep() {
  this.id = uid++
  this.subs = []
}

Dep.prototype = {
  addSub: function (sub) {
    this.subs.push(sub)
  },

  depend: function () {
    // 8.addDep函数中真正的让watcher和dep出现存储--> watcher.js
    Dep.target.addDep(this)
  },

  removeSub: function (sub) {
    var index = this.subs.indexOf(sub)
    if (index != -1) {
      this.subs.splice(index, 1)
    }
  },

  notify: function () {
    this.subs.forEach(function (sub) {
      sub.update()
    })
  },
}

Dep.target = null
